﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DataAccessLayer;

namespace BusinessComponents.Implementation
{
    class BookingBLL
    {
        private BookingRepository bookingRepository = new BookingRepository();
        private BookingDetailsRepository bookingDetailRepository = new BookingDetailsRepository();
        private RoomTypeRepository roomTypeRepository = new RoomTypeRepository();
        private GuestRepository guestRepository = new GuestRepository();
        private EmailBLL emailBLL = new EmailBLL();

        private bool isValid = true;
        private string errorMessage = string.Empty;

        public bool IsValid
        {
            get { return isValid; }
        }

        public string ErrorMessage
        {
            get { return errorMessage; }
        }

        private void SetError(string message)
        {
            isValid = false;
            errorMessage += message + Environment.NewLine;
        }

        public string MakeReservation(Booking booking)
        {
            bool valid = true;
            string errorMessage = string.Empty;

            // Booking
            Booking newBooking = new Booking();
            newBooking.MakeBooking(booking);

            if (!booking.IsValid)
            {
                SetError(booking.ErrorMessage);
            }

            // Guest
            if (isValid && booking.Guests.Count == 1)
            {
                Guest firstGuest = new Guest();
                firstGuest.SetGuestInformation(booking.Guests.ElementAt(0), true);

                if (!firstGuest.IsValid)
                {
                    SetError(firstGuest.ErrorMessage);
                }
            }
            else
            {
                Guest firstGuest = new Guest();
                firstGuest.SetGuestInformation(booking.Guests.ElementAt(0), true);

                if (!firstGuest.IsValid)
                {
                    SetError(firstGuest.ErrorMessage);
                }
                else
                {
                    newBooking.Guests.Add(firstGuest);
                }

                Guest secondGuest = new Guest();
                secondGuest.SetGuestInformation(booking.Guests.ElementAt(1), false);

                if (!secondGuest.IsValid)
                {
                    SetError(secondGuest.ErrorMessage);
                }
                else
                {
                    newBooking.Guests.Add(secondGuest);
                }
            }

            // Payment
            if (isValid && booking.Payment != null)
            {
                Payment payment = new Payment();
                payment.MakePayment(booking.Payment, booking.Guests.ElementAt(0));

                if (!payment.IsValid)
                {
                    SetError(payment.ErrorMessage);
                }
                else
                {
                    newBooking.Payment = payment;
                }
            }

            if (isValid && newBooking.IsValid)
            {
                bookingRepository.Add(newBooking);
                bookingRepository.Commit();
            }

            if (isValid)
            {
                SendConfirmationEmail(newBooking);
            }

            if (isValid)
            {
                return newBooking.BookingNumber;
            }
            else
            {
                return null;
            }
        }

        public IEnumerable<Booking> FindBookingByGuestID(int GuestId)
        {
          //  return bookingRepository.GetAll().Where(o => o.Guest.ID == GuestId);
            return bookingRepository.GetAll().Where(o => o.Guests.Where(g => g.ID == GuestId).Count() > 0);
        }


        //    return from b in findAllBooking()
        //           join bg in
        //               (
        //                   from bg in bookingGuest.FindByGuestID(GuestId) select bg)
        //               on b.ID equals bg.BookingID into ood
        //           from od in ood.DefaultIfEmpty()

        //           select b;

        //}

        public IEnumerable<Booking> FindBookingByGuestName(String GuestName)
        {

            return bookingRepository.GetAll().Where(o => o.Guests.Where(g => g.FirstName.StartsWith(GuestName) || g.LastName.StartsWith(GuestName)).Count() > 0);
 
            //BookingGuestBLL bookingGuest = new BookingGuestBLL();
            //GuestBLL guest = new GuestBLL(); 
            //return from b in findAllBooking()
            //       join bg in
            //           (
            //               from bg in bookingGuest.FindALLBookingGuest() join g in guest.FindGuestByName(GuestName) on bg.GuestID equals g.ID select bg)
            //           on b.ID equals bg.BookingID into ood
            //       from od in ood.DefaultIfEmpty()
                  
            //       select b;


            //bookings =  bookingRepository.GetAll().Where(o => o.Guest.FirstName.StartsWith(GuestName)||o.Guest.LastName.StartsWith(GuestName) );
            //return bookings;
        }

        public IEnumerable<Booking> findAllBooking()
        {
            BookingRepository repo = new BookingRepository();
           return repo.GetAll();
        }

        public IEnumerable<Booking> findBooking(DateTime StartDate, DateTime EndDate, String GuestName)
        {
            if (EndDate == null || EndDate == DateTime.MinValue)
                EndDate = DateTime.MaxValue;
            if (StartDate == null || StartDate == DateTime.MinValue)
                StartDate = DateTime.MinValue;
             
            IEnumerable<Booking> dateRange = findBookingInRange(StartDate, EndDate);

            if (String.IsNullOrEmpty(GuestName))
                return dateRange;
            else 
                return findBookingInRange(StartDate, EndDate).Where(o => o.Guests.Where(g => g.FirstName.StartsWith(GuestName) || g.LastName.StartsWith(GuestName)).Count() > 0);
    
        }

        public bool IsEmpty<T>(IEnumerable<T> data)
        {
            return data == null || !data.Any();
        }

        public IEnumerable<Booking> findBookingInRange(DateTime StartDate, DateTime EndDate)
        {

            IEnumerable<Booking> bookings =  findAllBooking();
            
           return from a in  findAllBooking()
                        where (
                        (a.StartDate <=   StartDate && StartDate < a.EndDate) ||
                        (a.StartDate < EndDate && EndDate <= a.EndDate) ||
                        (a.StartDate > StartDate && a.EndDate <= EndDate)
                        )
                        select a;
        }

        public Booking findBooking(int id)
        {
            BookingRepository repo = new BookingRepository();
            return repo.FindById(id);
           
        }

        public IEnumerable<Guest> findBookingGuestbyBookingID(int bookingid)
        {
            GuestRepository guestRepo = new GuestRepository();
            return guestRepo.FindByBookingId(bookingid);
            
        }

        public bool isBookingCancelable(int id)
        {
            BookingRepository repo = new BookingRepository();
            Booking  booking= repo.FindById(id);
            if (booking != null && booking.StartDate != null)
            {
                if (booking.StartDate.Value.AddDays(-3) >= System.DateTime.Now)
                {
                    if (booking.BookingStatus.ToUpper() != "CANCEL")
                    {
                        return true;
                    }
                }
                else
                    return false;
            }
            return false;

        }

        public bool isBookingUpdateable(int id)
        {
            BookingRepository repo = new BookingRepository();
            Booking booking = repo.FindById(id);
            if (booking != null && booking.StartDate != null)
            {
                if (booking.StartDate > System.DateTime.Now)
                {
                    if (booking.BookingStatus.ToUpper() != "CANCEL")
                    {
                        return true;
                    }
                }
                else
                    return false;
            }
            return false;
        }

        private void SendConfirmationEmail(Booking booking)
        {
            emailBLL.sendEmail(booking, booking.Guest, "http://localhost:7777/");
        }

        public Booking FindByBookingNumber(string bookingNumber)
        {
            return bookingRepository.FindByBookingNumber(bookingNumber);
        }
    }
}
